package com.han.util;

import cn.hutool.core.util.StrUtil;
import com.han.service.impl.MysqlService;
import freemarker.template.*;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.sql.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 代码生成工具
 *
 * @author Administrator
 */
public class Generator {

    public Generator() {

    }

    //private static Connection connection = null;

    private static final Map<String, String> jdbcToJavaType = new HashMap<String, String>();

    static {
//        https://www.cnblogs.com/loveer/p/11604423.html
        MysqlService mysqlService = new MysqlService();
        //jdbc类型到java类型的转换 有问题再去调整把。 健壮的转换方法还是要去看看别的框架比如Mybatis jooq这些是怎么做的
        //初始化jdbc类型转换。
        jdbcToJavaType.put("VARCHAR", "String");
        jdbcToJavaType.put("CHAR", "String");
        jdbcToJavaType.put("VARCHAR2", "String");
        jdbcToJavaType.put("NVARCHAR", "String");
        jdbcToJavaType.put("LONGNVARCHAR", "String");
        jdbcToJavaType.put("TEXT", "String");
        jdbcToJavaType.put("TINYTEXT", "String");
        jdbcToJavaType.put("MEDIUMTEXT", "String");
        jdbcToJavaType.put("LONGTEXT", "String");
        jdbcToJavaType.put("CLOB", "String");
        jdbcToJavaType.put("TINYLOB", "String");


        //数据库查出来的都是装箱类型，如果java类型用int，会存在值类型转换失败的问题
        jdbcToJavaType.put("INT", "Integer");
        jdbcToJavaType.put("INT UNSIGNED", "Integer");  // UNSIGNED 代表无符号 无符号等于没有负数的  所以是没有负数的int
        jdbcToJavaType.put("INTEGER", "Integer");
        jdbcToJavaType.put("SMALLINT", "Integer");
        jdbcToJavaType.put("TINYINT", "Integer");
        jdbcToJavaType.put("TINYINT UNSIGNED", "Integer");
        jdbcToJavaType.put("BIGINT", "Long");
        jdbcToJavaType.put("BIGINT UNSIGNED", "Long");


        jdbcToJavaType.put("NUMBERIC", "Long");
        jdbcToJavaType.put("NUMBER", "Long");
        jdbcToJavaType.put("DOUBLE", "Double");
        jdbcToJavaType.put("FLOAT", "Float");

        jdbcToJavaType.put("DATE", "Date");
        jdbcToJavaType.put("DATETIME", "Date");//java.util.Date
        jdbcToJavaType.put("TIMESTAMP", "Timestamp");//java.sql.Timestamp

        // 待测试区

        jdbcToJavaType.put("MEDIUMBLOB", "Byte[]");
        jdbcToJavaType.put("BLOB", "Byte[]");
        jdbcToJavaType.put("LONGBLOB", "Byte[]");
        jdbcToJavaType.put("VARBINARY", "Byte[]");
        jdbcToJavaType.put("ENUM", "String"); // 待测试
        jdbcToJavaType.put("SET", "String"); // 待测试


        // Boolean
        jdbcToJavaType.put("BIT", "Boolean");
    }

    private static final Map<String, String> jdbcMybatisType = new HashMap<String, String>();

    static {
        jdbcMybatisType.put("INT", "INTEGER");
        jdbcMybatisType.put("DATETIME", "TIMESTAMP");
    }

    private static final Map<String, String> javaType = new HashMap<String, String>();

    static {
        String str = "str";
        String number = "int";
        //初始化jdbc类型转换。
        javaType.put("VARCHAR", str);
        javaType.put("CHAR", str);
        javaType.put("VARCHAR2", str);
        javaType.put("NVARCHAR", str);
        javaType.put("LONGNVARCHAR", str);
        javaType.put("TEXT", str);
        javaType.put("CLOB", str);
        javaType.put("TINYLOB", str);
        //数据库查出来的都是装箱类型，如果java类型用int，会存在值类型转换失败的问题
        javaType.put("INT", number);
        javaType.put("INTEGER", number);
        javaType.put("SMALLINT", number);
        javaType.put("TINYINT", number);
        javaType.put("BIGINT", number);

        javaType.put("NUMBERIC", number);
        javaType.put("NUMBER", number);
//        javaType.put("DOUBLE", "Double");
//        javaType.put("FLOAT", "Float");
//
//        javaType.put("DATE", "Date");
//        javaType.put("DATETIME", "Date");//java.util.Date
//        javaType.put("TIMESTAMP", "Timestamp");//java.sql.Timestamp
    }

    public void generate() throws Exception {
        CGUtil.delFile();
        Version version = new Version("2.3.27");
        // 这个版本号不知道是干吗的。https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#Configuration-freemarker.template.Version-
        Configuration conf = new Configuration(version);
        conf.setDefaultEncoding("UTF-8");
        conf.setObjectWrapper(new DefaultObjectWrapper(version));
        File file = ClassPathResourceLocalUtil.getFile("/" + CGConstants.propLocation);
        conf.setDirectoryForTemplateLoading(file);
//		String tableName = PropLoader.getPlanProp("db.tableName");
//		String moduleName = scanner("模块名");
//		String[] tableNames = scanner("表名，多个英文逗号分割").split(",");
//        String[] tableNames = ("dsg_data_cooperation_personnel_account," +
//                "dsg_data_cooperation_personnel_account_history," +
//                "dsg_data_partner_personnel_audit," +
//                "dsg_personnel_management_of_data_partners," +
//                "dsg_personnel_management_of_data_partners_history").split(",");
//        for (String tableName : tableNames) {
//          百分号可以进行模糊匹配  ， "abc_%" ： 可以匹配acb_开头的表名
        List<String> tableNames = new ArrayList<>();
        String tableName = "dsg_assessment_template";
        if (tableName.endsWith("*")) {
            tableName = tableName.replace("*", "%");
            ResultSet tables = getTableResultSet(tableName);
            while (tables.next()) {
                tableNames.add(tables.getString("TABLE_NAME"));
            }
        } else {
            tableNames.add(tableName);
        }

        CGUtil.infoLog(tableNames.toString());
        for (String name : tableNames) {
            generateCode(conf, name);
        }
        generatePageDTO(conf);
        generateResuleVo(conf);

        // freemarker测试
        // generateTest(conf,tableName);


    }

    private ResultSet getTableResultSet(String tableName) throws Exception {
        Connection con = DBUtil.getDBConn();
        DatabaseMetaData metaData = con.getMetaData();
        ResultSet tables = null;
        try {
            String schema = PropLoader.getProp().contains("jdbc.schema") ? PropLoader.getProp("jdbc.schema") : null;
            tables = metaData.getTables(schema, "%", tableName, new String[]{"TABLE"});
        } finally {
            HanConnectionUtil.closeConnection(con);
        }

        return tables;
    }

    private void generatePageDTO(Configuration conf) throws IOException, TemplateException {
        Template template = conf.getTemplate("PageDTO.ftl");
        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/PageDTO.java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(null, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("====  表对应的 通用返回结果类生成成功 生成地址：" + pojoLocation + " ====");
    }

    public void generateCode(Configuration conf, String tableName) throws Exception {
        Map<String, Object> paramMap = this.getCommonParam(tableName);
        this.addTableInfo(paramMap, tableName);
        paramMap.put("system", "sdds");
        // 生成POJO类
        generatePOJO(conf, tableName, paramMap);
        generateQueryParam(conf, tableName, paramMap);
        generateVo(conf, tableName, paramMap);
        generateExcel(conf, tableName, paramMap);


        // 生成service接口类
        generateService(conf, tableName, paramMap);
        // 生成serviceimpl实现类
        generateServiceImpl(conf, tableName, paramMap);
        // 生成Controller
        generateController(conf, tableName, paramMap);
        // 生成 mapper 接口类
        generateMyBatisMapper(conf, tableName, paramMap);
        // 生成 MapperXml  文件
        generateMyBatisXml(conf, tableName, paramMap);
        // 生成页面
        generatePage(conf, tableName, paramMap);
        // 生成config.js的配置建议
        generatePageConf(conf, tableName, paramMap);
    }

    private void generateExcel(Configuration conf, String tableName, Map<String, Object> paramMap) throws IOException, TemplateException {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的 QueryParam ====");
        Template template = conf.getTemplate("Excel.ftl");
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.orderby"))) {
//			paramMap.put("table_order_by", PropLoader.getPlanProp("db.orderby"));
//		}
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.order"))) {
//			paramMap.put("table_order", PropLoader.getPlanProp("db.order"));
//		}
        String pojoName = paramMap.get("pojo_name").toString();
//        this.addTableInfo(paramMap, tableName);

        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/" + pojoName + "Excel.java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的 Excel 类生成成功 生成地址：" + pojoLocation + " ====");
    }

    private void generateResuleVo(Configuration conf) throws IOException, TemplateException {
        Template template = conf.getTemplate("ResultBean.ftl");
        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/ResultBean.java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(null, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("====  表对应的 通用返回结果类生成成功 生成地址：" + pojoLocation + " ====");
    }


    /**
     * 读取控制台内容信息
     */
    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        CGUtil.infoLog(("请输入" + tip + "："));
        if (scanner.hasNext()) {
            String next = scanner.next();
            if (StrUtil.isNotEmpty(next)) {
                return next;
            }
        }
        throw new RuntimeException("请输入正确的" + tip + "！");
    }

    private void generateMyBatisXml(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的 MapperXml 文件 ====");
        Template template = null;
        String system = (String) paramMap.get("system");
        if (system != null && system.equals("sdds")) {
            template = conf.getTemplate("Mapper_Mybatis_Plus_xml.ftl");
        } else {
            template = conf.getTemplate("Mapper_Mybatis_xml.ftl");
        }
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();

//        this.addTableInfo(paramMap, tableName);

        // 生成文件
        String folderLocation = CGConstants.MapperXmlLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String serviceLocation = folderLocation + "/" + pojoName + "MapperXml.xml";
        Writer writer = new OutputStreamWriter(new FileOutputStream(serviceLocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的 Mapper 接口类生成成功 生成地址：" + serviceLocation + " ====");
    }

    private void generateMyBatisMapper(Configuration conf, String tableName, Map<String, Object> paramMap) throws IOException, TemplateException {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的 mapper 接口 ====");
        Template template = null;
        String system = (String) paramMap.get("system");
        if (system != null && system.equals("sdds")) {
            template = conf.getTemplate("Mapper_Mybatis_Plus_java.ftl");
        } else {
            template = conf.getTemplate("Mapper_Mybatis_java.ftl");
        }

        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();
        // 生成文件
        String folderLocation = CGConstants.MapperLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String serviceLocation = folderLocation + "/" + pojoName + "Mapper.java";
        Writer writer = new OutputStreamWriter(new FileOutputStream(serviceLocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的 Mapper 接口类生成成功 生成地址：" + serviceLocation + " ====");
    }

    private void generatePageConf(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        // TODO Auto-generated method stub
        Template template = conf.getTemplate("configjs.ftl");
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        Writer writer = new OutputStreamWriter(System.out, "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        //writer.close();
    }

    private void generatePage(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        //生成Html页面，html页面是变化最多的部分。目前的实现逻辑麻烦的就在查询条件那一部分， 初期的最初实现就把POJO中配置了TableColumn属性的列全部生成为文本类型的查询条件， 以后再优化。
        CGUtil.infoLog("==== 开始生成 " + tableName + " 对应的管理页面 ====");
        Template template = conf.getTemplate("Html.ftl");
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();
        //添加html相关参数。
        this.addHtmlInfo(paramMap, tableName);

        // 生成文件
        String folderLocation = CGConstants.HtmlLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String filelocation = folderLocation + "/" + pojoName + ".html";
        Writer writer = new OutputStreamWriter(new FileOutputStream(filelocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 对应的管理页面生成成功 生成地址：" + filelocation + " ====");
    }

    private void generateController(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的Controller实现类 ====");
        Template template = null;
        String system = (String) paramMap.get("system");
        if (system != null && system.equals("sdds")) {
            template = conf.getTemplate("Controller_Mybatis_Plus_java.ftl");
        } else {
            template = conf.getTemplate("Controller_Mybatis_java.ftl");
        }

        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();
//        this.addTableInfo(paramMap, tableName);
        // 生成文件
        String folderLocation = CGConstants.ControllerLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String serviceLocation = folderLocation + "/" + pojoName + "Controller.java";
        Writer writer = new OutputStreamWriter(new FileOutputStream(serviceLocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的Service接口类生成成功 生成地址：" + serviceLocation + " ====");
    }

    private void generateServiceImpl(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的serviceImpl实现类 ====");
        Template template = null;
        String system = (String) paramMap.get("system");
        if (system != null && system.equals("sdds")) {
            template = conf.getTemplate("ServiceImpl_Mybatis_Plus.ftl");
        } else {
            template = conf.getTemplate("ServiceImpl_Mybatis.ftl");
        }
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();
        // 生成文件
        String folderLocation = CGConstants.ServiceImplLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String serviceLocation = folderLocation + "/" + pojoName + "ServiceImpl.java";
        Writer writer = new OutputStreamWriter(new FileOutputStream(serviceLocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的Service接口类生成成功 生成地址：" + serviceLocation + " ====");
    }

    private void generateService(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的service接口 ====");
        Template template = conf.getTemplate("Service.ftl");
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
        String pojoName = paramMap.get("pojo_name").toString();
        String moduleName = paramMap.get("module_name").toString();
        // 生成文件
        String folderLocation = CGConstants.ServiceLocation + "/" + moduleName;
        File filefolder = new File(folderLocation);
        if (!filefolder.exists()) {
            filefolder.mkdirs();
        }
        String serviceLocation = folderLocation + "/" + pojoName + "Service.java";
        Writer writer = new OutputStreamWriter(new FileOutputStream(serviceLocation), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的Service接口类生成成功 生成地址：" + serviceLocation + " ====");
    }

    private void generatePOJO(Configuration conf, String tableName, Map<String, Object> paramMap)
            throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的POJO ====");
        Template template = conf.getTemplate("Pojo.ftl");
        // 拼凑参数
        if (StringUtils.isNotBlank(PropLoader.getPlanProp("db.orderby"))) {
            paramMap.put("table_order_by", PropLoader.getPlanProp("db.orderby"));
        }
        if (StringUtils.isNotBlank(PropLoader.getPlanProp("db.order"))) {
            paramMap.put("table_order", PropLoader.getPlanProp("db.order"));
        }
        String pojoName = paramMap.get("pojo_name").toString();


        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/" + pojoName + ".java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的POJO类生成成功 生成地址：" + pojoLocation + " ====");
    }

    private void generateVo(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的 QueryParam ====");
        Template template = conf.getTemplate("Vo.ftl");
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.orderby"))) {
//			paramMap.put("table_order_by", PropLoader.getPlanProp("db.orderby"));
//		}
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.order"))) {
//			paramMap.put("table_order", PropLoader.getPlanProp("db.order"));
//		}
        String pojoName = paramMap.get("pojo_name").toString();

//        this.addTableInfo(paramMap, tableName);

        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/" + pojoName + "Vo.java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的 QueryParam 类生成成功 生成地址：" + pojoLocation + " ====");
    }

    private void generateQueryParam(Configuration conf, String tableName, Map<String, Object> paramMap) throws Exception {
        CGUtil.infoLog("==== 开始生成 " + tableName + " 表对应的 QueryParam ====");
        Template template = conf.getTemplate("QueryParam.ftl");
        // 拼凑参数
//        Map<String, Object> paramMap = this.getCommonParam(tableName);
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.orderby"))) {
//			paramMap.put("table_order_by", PropLoader.getPlanProp("db.orderby"));
//		}
//		if(StringUtils.isNotBlank(PropLoader.getPlanProp("db.order"))) {
//			paramMap.put("table_order", PropLoader.getPlanProp("db.order"));
//		}
        String pojoName = paramMap.get("pojo_name").toString();
//        this.addTableInfo(paramMap, tableName);

        // 生成文件
        String pojoLocation = CGConstants.POJOLocation + "/" + pojoName + "QueryParam.java";
        File pojoFile = new File(pojoLocation);
        Writer writer = new OutputStreamWriter(new FileOutputStream(pojoFile), "UTF-8");
        //Writer writer = new OutputStreamWriter(new FileOutputStream(pojoName + ".java"), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
        CGUtil.infoLog("==== " + tableName + " 表对应的 QueryParam 类生成成功 生成地址：" + pojoLocation + " ====");
    }

    // freemarker测试
    private void generateTest(Configuration conf, String tableName) throws TemplateException, IOException {
        Template template = conf.getTemplate("test.ftl");
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("description", "我正在学习使用Freemarker生成静态文件！");

        List<String> nameList = new ArrayList<String>();
        nameList.add("陈靖仇");
        nameList.add("玉儿");
        nameList.add("宇文拓");
        paramMap.put("nameList", nameList);

        Map<String, Object> weaponMap = new HashMap<String, Object>();
        weaponMap.put("first", "轩辕剑");
        weaponMap.put("second", "崆峒印");
        weaponMap.put("third", "女娲石");
        weaponMap.put("fourth", "神农鼎");
        weaponMap.put("fifth", "伏羲琴");
        weaponMap.put("sixth", "昆仑镜");
        weaponMap.put("seventh", null);
        paramMap.put("weaponMap", weaponMap);

        Writer writer = new OutputStreamWriter(new FileOutputStream("../genauth/success.html"), "UTF-8");
        template.process(paramMap, writer);
        writer.flush();
        writer.close();
    }

    // 一些公用的参数就一起封装一下。
    private Map<String, Object> getCommonParam(String tableName) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("pojo_name", CGUtil.getPOJONameByTableName(tableName));
        paramMap.put("pojo_field_name", CGUtil.getCamelName(tableName));

        paramMap.put("pojo_name_vo", CGUtil.getPOJONameByTableName(tableName)+"Vo");
        paramMap.put("pojo_field_name_vo", CGUtil.getCamelName(tableName)+"Vo");

        paramMap.put("pojo_name_Excel", CGUtil.getPOJONameByTableName(tableName)+"Excel");
        paramMap.put("pojo_field_name_Excel", CGUtil.getCamelName(tableName)+"Excel");

        paramMap.put("pojo_name_query_param", CGUtil.getPOJONameByTableName(tableName)+"QueryParam");
        paramMap.put("pojo_field_name_query_param", CGUtil.getCamelName(tableName)+"QueryParam");

        paramMap.put("pojo_name_mapper", CGUtil.getPOJONameByTableName(tableName)+"Mapper");
        paramMap.put("pojo_field_name_mapper", CGUtil.getCamelName(tableName)+"Mapper");

        paramMap.put("pojo_name_service", CGUtil.getPOJONameByTableName(tableName)+"Service");
        paramMap.put("pojo_field_name_service", CGUtil.getCamelName(tableName)+"Service");

        paramMap.put("pojo_name_service_impl", CGUtil.getPOJONameByTableName(tableName)+"ServiceImpl");
        paramMap.put("pojo_field_name_service_impl", CGUtil.getCamelName(tableName)+"ServiceImpl");

        String moduleName = PropLoader.getPlanProp("plan.moduleName");
        paramMap.put("module_name", moduleName);
        String genTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        paramMap.put("gen_time", genTime);
        paramMap.put("table_name", tableName);
        paramMap.put("package", "com.han.client.demo.");
        paramMap.put("requestUrlPrefix", "/stap/dsg/dataSecurityAssessment/");
        return paramMap;
    }

    //获取表结构信息 主要是表名、表注释、字段名，字段类型， 字段注释。
    private void addTableInfo(Map<String, Object> paramMap, String tableName) throws Exception {
        // TODO Auto-generated method stub
        Connection con = DBUtil.getDBConn();
        DatabaseMetaData meta = con.getMetaData();
        ResultSet tableSet = null;
        ResultSet columnSet = null;
        ResultSet primaryKeySet = null;
        List<String> excelImportFields = new ArrayList<>();
        try {
            //获取表信息
            String schema = PropLoader.getProp().contains("jdbc.schema") ? PropLoader.getProp("jdbc.schema") : null;
            tableSet = getTableResultSet(tableName);
            if (tableSet.next()) {//只取查到的第一条数据
                if(!tableName.equals(tableSet.getString("TABLE_NAME"))){
                    throw new Exception("数据库中没有查到表 " + tableName);
                }
                paramMap.put("table_name_small", tableSet.getString("TABLE_NAME"));
                paramMap.put("table_remark", tableSet.getString("REMARKS"));
                CGUtil.infoLog("获取到表信息 TABLE_NAME => " + tableSet.getString("TABLE_NAME") + ";TABLE_REMARK => " + tableSet.getString("REMARKS"));
            } else {
                CGUtil.errorLog("数据库中没有查到表 " + tableName);
                throw new Exception("数据库中没有查到表 " + tableName);
            }
            List<String> primaryKeys = null;
            //加载主键。
            if (null == primaryKeys || primaryKeys.size() == 0) {
                primaryKeys = new ArrayList<String>();//主键列名
                primaryKeySet = meta.getPrimaryKeys(schema, "%", tableName);
                while (primaryKeySet.next()) {
                    primaryKeys.add(primaryKeySet.getString("COLUMN_NAME"));
                }
            }
            //获取字段信息
            columnSet = meta.getColumns(schema, "%", tableName, "%");
            List<Map<String, Object>> columns = new ArrayList<Map<String, Object>>();
            while (columnSet.next()) {
                Map<String, Object> columnInfo = new HashMap<String, Object>();
                String columnName = columnSet.getString("COLUMN_NAME");
                String columnType = columnSet.getString("TYPE_NAME");
                int datasize = columnSet.getInt("COLUMN_SIZE");
                int digits = columnSet.getInt("DECIMAL_DIGITS");
                int nullable = columnSet.getInt("NULLABLE");
                String remarks = columnSet.getString("REMARKS");
                CGUtil.infoLog("获取到字段信息 ： columnName =>" + columnName + ";columnType => " + columnType + ";datasize=>" + datasize + "=>" + digits + ";nullable => " + nullable + ";remarks => " + remarks);
                //只对JDBC几种常见的数据类型做下匹配，其他不常用的就暂时不生成了。 健壮的类型映射还是需要看下别的框架是怎么做的。
                if (StringUtils.isNotBlank(columnType)
                        && jdbcToJavaType.containsKey(columnType.toUpperCase())) {
                    columnInfo.put("columnName", columnName);
                    if (jdbcMybatisType.containsKey(columnType.toUpperCase())) {
                        columnInfo.put("columnType", jdbcMybatisType.get(columnType.toUpperCase()));
                    } else {
                        columnInfo.put("columnType", columnType);
                    }
                    columnInfo.put("javaType", jdbcToJavaType.get(columnType.toUpperCase()));
                    String javaName = CGUtil.getCamelName(columnName);
                    String methodName = CGUtil.getUpperFirst(javaName);
                    columnInfo.put("javaName", javaName);
                    columnInfo.put("getterName", "get" + methodName);
                    columnInfo.put("setterName", "set" + methodName);
                    if ("Long".equals(jdbcToJavaType.get(columnType.toUpperCase()))){
                        columnInfo.put("javaNameStr", javaName+"Str");
                        columnInfo.put("javaTypeStr", "String");
                        columnInfo.put("getterNameStr", "get" + methodName+"Str");
                        columnInfo.put("setterNameStr", "set" + methodName+"Str");
                    }

                    if (!javaName.toLowerCase().contains("id")
                            && !primaryKeys.contains(columnName)
                            && !javaName.toLowerCase().contains("time")){
                        columnInfo.put("javaNameExclude", "exclude"+methodName);
                        columnInfo.put("getterNameExclude", "getExclude" + methodName);
                        columnInfo.put("setterNameExclude", "setExclude" + methodName);
                    }
                    if (!primaryKeys.contains(columnName)){
                        columnInfo.put("javaNameExcel", javaName);
                        columnInfo.put("javaTypeExcel", "String");
                        excelImportFields.add(remarks);
                    }

                    columnInfo.put("remarks", StringUtils.isNotBlank(remarks) ? remarks.trim() : "");
                    columnInfo.put("isPK", primaryKeys.contains(columnName) ? "true" : "");
                    if (javaType.containsKey(columnType.toUpperCase())) {
                        columnInfo.put("type", javaType.get(columnType.toUpperCase()));
                    } else {
                        columnInfo.put("type", jdbcToJavaType.get(columnType.toUpperCase()));
                    }
                    columns.add(columnInfo);
                } else {
                    CGUtil.infoLog("字段信息 ： columnName =>" + columnName + " 类型 columnType => " + columnType + " 暂无法处理，待以后进行扩展 ;");
                    throw new Exception("表名为 " + tableName + " 字段信息 ： columnName =>" + columnName + " 类型 columnType => " + columnType + " 暂无法处理，待以后进行扩展 ;");
                }

            }
            paramMap.put("COLUMNS", columns);
            paramMap.put("excelImportFields", excelImportFields);
        } finally {
            HanConnectionUtil.closeResultSet(tableSet);
            HanConnectionUtil.closeResultSet(columnSet);
            HanConnectionUtil.closeResultSet(primaryKeySet);
            HanConnectionUtil.closeConnection(con);
        }
        //获取表主键信息
        //ResultSet primaryKeys = meta.getPrimaryKeys(null, schema, tableName);

    }

    private void addHtmlInfo(Map<String, Object> paramMap, String tableName) throws Exception {
        List<List<Map<String, Object>>> allModules = new ArrayList<List<Map<String, Object>>>();//所有控件
        Connection con = DBUtil.getDBConn();
        DatabaseMetaData meta = con.getMetaData();
        String schema = PropLoader.getProp().contains("jdbc.schema") ? PropLoader.getProp("jdbc.schema") : null;
        ResultSet columnSet = null;
        try {
            columnSet = meta.getColumns(schema, "%", tableName, "%");
            int rowIndex = 0;
            List<Map<String, Object>> rowModules = null;//每一行的查询控件。 每行默认四个。

            while (columnSet.next()) {
                String remarks = columnSet.getString("REMARKS");
                String columnName = columnSet.getString("COLUMN_NAME");
                String columnTypeName = columnSet.getString("TYPE_NAME");
                String javaName = CGUtil.getCamelName(columnName);
//                String moduleIsPk = primaryKeys.contains(columnName) ? "true" : "false";

                Map<String, Object> module = new HashMap<String, Object>();
                //页面每一行默认放四个查询控件。
                if (rowIndex % 4 == 0) {
                    CGUtil.infoLog("管理页面生成：查询条件换行");
                    if (null != rowModules) {
                        allModules.add(rowModules);
                    }
                    rowModules = new ArrayList<Map<String, Object>>();
                }
                //查询控件的标签用字段的注释，如果没有注释就直接放字段名了。
                String condRemark = StringUtils.isBlank(remarks) ? columnName : remarks;
                module.put("remarks", condRemark);
                module.put("java_name", javaName);
                module.put("type_name", columnTypeName);
//                module.put("isPK", moduleIsPk);
                module.put("isPK", "false");
                rowModules.add(module);
                CGUtil.infoLog("管理页面生成：加载查询条件： columnName => " + columnName + ";标签 =>" + condRemark + ";对应属性 => " + javaName);
                rowIndex++;
            }
            if (rowModules.size() > 0) {
                allModules.add(rowModules);
            }

        } finally {
            HanConnectionUtil.closeResultSet(columnSet);
            HanConnectionUtil.closeConnection(con);
        }
        paramMap.put("all_modules", allModules);
    }

    public static void main(String[] args) throws Exception {
        //mysql
        Class.forName("com.mysql.cj.jdbc.Driver");
        Properties props = new Properties();
        props.put("useInformationSchema", "true"); //mysql获取表注释需要加上这个属性 
        props.put("user", "root");
        props.put("password", "root");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/genserver?serverTimezone=GMT%2B8&characterEncoding=utf-8&autoReconnect=true", props);
        //oracle
//		Class.forName("oracle.jdbc.driver.OracleDriver");
//		Connection con = DriverManager.getConnection("jdbc:oracle:thin:@172.16.49.65:1521/motion","swordrisk","risk#230");
//		Connection con = DriverManager.getConnection("jdbc:oracle:thin:@172.16.49.65:1521/motion","swordui","swo#1234");

//		 Properties props = new Properties();  
//         props.put("remarksReporting", "true");  //要获取注释，需要增加这个属性。
//         props.put("user", "swordrisk");  
//         props.put("password", "risk#230");  
//         Connection con = DriverManager.getConnection("jdbc:oracle:thin:@172.16.49.65:1521/motion",props);
        CGUtil.infoLog("========映射表信息==============");
        DatabaseMetaData meta = con.getMetaData();
        ResultSet tables = meta.getTables("genserver", "%", "black_info", new String[]{"TABLE"});
        while (tables.next()) {
            ResultSetMetaData metaData = tables.getMetaData();
            CGUtil.infoLog(metaData.getColumnCount());
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                CGUtil.infoLog(metaData.getColumnName(i) + " ==> " + tables.getString(metaData.getColumnName(i)));
            }

            CGUtil.infoLog(tables.getString("TABLE_NAME") + " --->>> " + tables.getString("REMARKS"));
        }
        CGUtil.infoLog("========映射列信息==============");
        ResultSet columns = meta.getColumns("genserver", "%", "black_info", "%");
        CGUtil.infoLog("columnName|columnType|datasize|digits|nullable|remarks");
        while (columns.next()) {
            String columnName = columns.getString("COLUMN_NAME");
            String columnType = columns.getString("TYPE_NAME");
            int datasize = columns.getInt("COLUMN_SIZE");
            int digits = columns.getInt("DECIMAL_DIGITS");
            int nullable = columns.getInt("NULLABLE");
            String remarks = columns.getString("REMARKS");
            CGUtil.infoLog(columnName + "|" + columnType + "|" + datasize + "|" + digits + "|" + nullable + "|" + remarks);
        }
        CGUtil.infoLog("========映射主键信息==============");
        ResultSet primaryKeys = meta.getPrimaryKeys("genserver", "%", "black_info");
        while (primaryKeys.next()) {
            ResultSetMetaData metaData = primaryKeys.getMetaData();
            CGUtil.infoLog("主键个数：" + metaData.getColumnCount());
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                CGUtil.infoLog(metaData.getColumnName(i) + " ==> " + primaryKeys.getString(metaData.getColumnName(i)));
            }
        }
    }
}
